#pragma once
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
using std::cout;
using std::endl;
extern Log log;

//简单的echo服务
class udp_server
{
private:
    int _sockfd;
    uint16_t _port = 8080;
    std::string _ip = "127.0.0.1";          //云服务器禁止直接绑定公网IP

public:
    udp_server(uint16_t port = 8080):_port(port){}
    ~udp_server(){if(_sockfd > 0)close(_sockfd); }

    void Init();            //建立连接
    void Run();             //开始通信
};


//1.建立连接: 创建套接字, bind套接字, 
void udp_server::Init()
{
    //创建套接字
    _sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    if(_sockfd < 0){ log(Fatal, "socket create fail"); exit(1); }
    log(Info , "socket create success: %d", _sockfd);

    //bind套接字
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(_port);                  //主机转网络
    server.sin_addr.s_addr = inet_addr(_ip.c_str()); //主机转网络
    int check = bind(_sockfd, (struct sockaddr*)&server, sizeof(server));

    if(check < 0){ log(Fatal, "bind socket fail"); exit(2);}
    log(Info , "bind socket success: %d", _sockfd);
}


//2.开始通信: recvfrom, sendto
void udp_server::Run()
{
    char inbuffer[1024];
    struct sockaddr_in client;
    while(1)
    {
        //服务端接收数据
        socklen_t len = sizeof(client);
        ssize_t recv_nums = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0 , (sockaddr*)&client, &len); //可能读取失败, 可以检测一下...
        inbuffer[recv_nums] = 0;
        cout << "client say " << inbuffer << endl;

        //服务端处理数据
        if(std::string(inbuffer) == "quit")break;

        std::string message = inbuffer;
        sendto(_sockfd, message.c_str(), message.size(), 0, (sockaddr*)&client, len);
        cout << "server say: " << message << endl;
        memset(inbuffer, 0 , sizeof(inbuffer));//清空
    }

    log(Info, "client quit");
}



